package com.haiertvbic.tvnow.protocol;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.ArrayList;

import com.haiertvbic.tvnow.model.ChannelBean;
import com.haiertvbic.tvnow.model.ChannelPagekageBean;
import com.haiertvbic.tvnow.model.LocalCodeBean;
import com.haiertvbic.tvnow.util.SLog;

public class SocketPackage {

	private static final String TAG = "FavChannel";
	// socketPackte对象定义
	private static SocketPackage socketPackte = null;
	private DataOutputStream dos = null;
	private DataInputStream dis = null;
	private Socket socket = null;

	/**
	 * 创建socketPackte对象
	 * 
	 * @return socketPackte
	 */
	public static SocketPackage getInstance() {
		if (null == socketPackte) {
			socketPackte = new SocketPackage();
		}
		return socketPackte;
	}

	public boolean isSocketAlive() {

		SLog.d(TAG, "SocketPackte.isSocketAlive.socket == " + socket);
		if (socket != null && !socket.isClosed()) {
			SLog.d(TAG, "SocketPackte.isSocketAlive.socket.isClosed() == "
					+ socket.isClosed());
			System.out
					.println("SocketPackte.isSocketAlive.socket.isConnected() == "
							+ socket.isConnected());
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 创建连接的方法，用于测试接口是否正确
	 * 
	 * @param ipString
	 *            主机名
	 * @param port
	 *            端口号
	 * @return
	 * @throws IOException
	 * @throws UnknownHostException
	 */
	public boolean createShortSocket(String ipString, int port) {
		try {
			if (socket != null && !socket.isClosed()) {
				socket.close();
			}
			socket = new Socket(ipString, port);
			if (socket != null) {
				dos = new DataOutputStream(socket.getOutputStream());
				dis = new DataInputStream(socket.getInputStream());
				return true;
			} else {
				return false;
			}
		} catch (IOException e) {
			// TODO: handle exception
			e.printStackTrace();
			return false;
		}

	}

	public void closeSocket() {
		SLog.d(TAG, "close socket method");
		if (null != socket) {
			try {
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		if (dis != null) {
			try {
				dis.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		if (dos != null) {
			try {
				dos.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

	}

	/**
	 * 向CAE发送请求消息
	 * 
	 * @param cmd_ID
	 *            消息的id 4位
	 * @param msgnum
	 *            消息的序号，可以为0 4位
	 * @param data
	 *            数据体
	 * @throws IOException
	 */
	public void sendPacket(int cmd_ID, int msgnum, ByteBuffer data)
			throws IOException {

		int packageLength = data.array().length;
		ByteBuffer byteBuffer = ByteBuffer.allocate(16 + packageLength);

		// 将id放入流
		byte[] idByte = new byte[4];
		idByte = ConnectManager.intToByte(cmd_ID);
		byteBuffer.put(idByte);

		// 将消息序号放入流
		byte[] msgnumByte = new byte[4];
		msgnumByte = ConnectManager.intToByte(msgnum);
		byteBuffer.put(msgnumByte);

		// 将保留位放入流
		byte[] reserveByte = new byte[4];
		byteBuffer.put(reserveByte);

		// 将数据长度放入流
		byte[] packagelength = new byte[4];
		packagelength = ConnectManager.intToByte(packageLength);
		byteBuffer.put(packagelength);

		byteBuffer.put(data.array());
		byte[] sb = byteBuffer.array();
		SLog.d(TAG, "socketpackte.sendpacket.send");
		dos.write(sb);
		byteBuffer.clear();
		dos.flush();
		SLog.d(TAG, "socketpackte.sendpacket.send finish");
	}

	/**
	 * 解析包头数据，根据消息ID获取频道和频道号列表。 连接成功的时候返回码为CAE返回的响应，而连接不成功则返回-200，表示socket连接有误。
	 * 
	 * @throws Exception
	 */
	public ChannelPagekageBean getTvChannelsFromCae() {
		ChannelPagekageBean channel_pagekage = null;
		// 定义返回数据
		ArrayList<ChannelBean> channels = null;
		try {
			// 解析包头的消息ID,根据这个id来判断是哪一个消息的返回值，并且解析响应的数据
			int cmd = dis.readInt();
			SLog.d(TAG, "socketpackte.getTvChannelsFromCae.cmd == " + cmd);
			// 包头消息不为空，解析数据（包头和包体）
			if (cmd == ConnectManager.CMD_CAE_APP_GET_AUDIO_RATE_RE) {
				// 消息序列号
				dis.readInt();
				// 保留字段
				dis.readInt();
				// 数据长度，不包含包体
				int date_length = dis.readInt();

				// 如果包体大于0，说明有数据，那么就解析他
				if (date_length > 0) {
					channel_pagekage = new ChannelPagekageBean();
					// 保存返回码
					int return_code;
					return_code = dis.readInt();
					SLog.d(TAG, "getTvChannelsFromCae.return_code == "
							+ return_code);
					channel_pagekage.setReturn_code(return_code);

					// 保存频道list
					channel_pagekage.setChannels(readFavBody());
				}

			}

		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			closeSocket();
		}
			return channel_pagekage;
	}

	/**
	 * 解析地域信息<br>
	 * 
	 * @return LocalCodeBean 地域信息对象<br>
	 * @throws Exception
	 */
	public LocalCodeBean getDeviceLocalInfo() {
		LocalCodeBean LocalInfo = null;
		try {
			// 解析包头的消息ID,根据这个id来判断是哪一个消息的返回值，并且解析响应的数据
			int cmd = dis.readInt();
			SLog.d(TAG, "socketpackte.getTvChannelsFromCae.cmd == " + cmd);
			if (cmd == ConnectManager.CMD_CAE_APP_GET_LOCAL_CODE_RE) {

				// 消息序列号
				dis.readInt();
				// 保留字段
				dis.readInt();
				// 数据长度，不包含包体
				int date_length = dis.readInt();
				// 以下为解析包体，这是提供给界面使用的
				if (date_length > 0) {
					LocalInfo = new LocalCodeBean();
					// 返回码
					int return_code = dis.readInt();
					LocalInfo.setReturn_code(return_code);
					SLog.d(TAG,"getTvChannelsFromCae.channel.return_code == "
							+ return_code);
					// 如果4006300就成功
					if (return_code == ConnectManager.LOC_SUC) {
						// 读取mac
						byte[] byte32 = new byte[32];
						dis.read(byte32);
						LocalInfo.setMac(new String(byte32, 0,
								byte32.length - 1));
						SLog.d(TAG,"getTvChannelsFromCae.channel.setMac == "
								+ LocalInfo.getMac());
						byte[] byte32_user = new byte[32];
						int len_user = dis.read(byte32_user);
						String count32 = new String(byte32_user, 0, len_user);
						int index = 0;
						for (int j = 0; j < count32.length(); j++) {
							if (0 == (count32.charAt(j))) {
								index = j;
								break;
							}
						}
						String user_account = count32.substring(0, index);
						LocalInfo.setUser_account(user_account);
						SLog.d(TAG, "getTvChannelsFromCae.channelName == "
								+ LocalInfo.getUser_account());

						byte[] byte8 = new byte[8];
						int len_version = dis.read(byte8);
						String version8 = new String(byte8, 0, len_version);
						int index_version = 0;
						for (int j = 0; j < version8.length(); j++) {
							if (0 == (version8.charAt(j))) {
								index_version = j;
								break;
							}
						}
						String version = version8.substring(0, index);
						LocalInfo.setVersion(version);
						SLog.d(TAG, "getTvChannelsFromCae.channelName == "
								+ LocalInfo.getVersion());

						// 国家
						LocalInfo.setState(dis.readInt());
						SLog.d(TAG, "getTvChannelsFromCae.channel.setState == "
								+ LocalInfo.getState());
						// 省
						LocalInfo.setProvince(dis.readInt());
						System.out
								.println("getTvChannelsFromCae.channel.setProvince == "
										+ LocalInfo.getProvince());
						// 市
						LocalInfo.setCity(dis.readInt());
						System.out
								.println("getTvChannelsFromCae.channel.setCity == "
										+ LocalInfo.getCity());
						// 区县
						LocalInfo.setStreet(dis.readInt());
						System.out
								.println("getTvChannelsFromCae.channel.setStreet == "
										+ LocalInfo.getStreet());
					}
				}
			} else {
				try {
					socket.sendUrgentData(0xff);
				} catch (IOException e) {// 与CAE的socket连接中断，重试。。。
					// 远程把连接中断
					closeSocket();
					return null;
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
			// 未知原因导致中断
			return null;
		}
		return LocalInfo;
	}

	/**
	 * 解析换台后的返回码，根据返回码不同，界面做出不同的响应
	 * 
	 * @return 0:读取换台信息失败 4004500:换台成功 4004501: 失败 ,此频道不存在 4004502:CRB 未插入，或者
	 *         CRB 故障 ， 提示用户插入或者重新插 拔 CRB 4004503 :未设置 CRB
	 */
	public int tvCurrentChannel() {
		int responseCode = 0;
		// 解析包头的消息ID,根据这个id来判断是哪一个消息的返回值，并且解析响应的数据
		try {
			int cmd = dis.readInt();
			SLog.d(TAG, "socketpackte.getTvChannelsFromCae.cmd == " + cmd);
			if (cmd == ConnectManager.CMD_SENT_CHANNEL_INFO_RE) {

				// 消息序列号
				dis.readInt();
				// 保留字段
				dis.readInt();
				// 数据长度，不包含包体
				int date_length = dis.readInt();

				// 解析包体，即返回码
				responseCode = dis.readInt();
				switch (responseCode) {
				case 4004500:// 换台成功
					responseCode = ConnectManager.CHANGE_CHANNEL_SUCCESS;
					break;
				case 4004501:// 换台失败，没有这个频道
					responseCode = ConnectManager.CHANGE_CHANNEL_FAIL;
					break;
				case 4004502:
					// CRB未插入，或者CRB故障，提示用户插入或者重新插拔CRB
					responseCode = ConnectManager.CHANGE_CHANNEL_NOCRB;
					break;
				case 4004503:
					// 未设置CRB
					responseCode = ConnectManager.CHANGE_CHANNEL_NOREMOUTESETTING;
					break;
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			responseCode = 0;
			e.printStackTrace();
		}
		return responseCode;
	}

	/**
	 * 读取最喜爱五个频道的包体的内容
	 * 
	 * @param channels
	 * @param dis
	 * @param return_code
	 * @throws Exception
	 */
	private ArrayList<ChannelBean> readFavBody() {
		ArrayList<ChannelBean> channels = new ArrayList<ChannelBean>();
		// 根据返回码判断是否成功4006000表示成功
		try {
			// 获取频道个数
			int channel_account = dis.readInt();
			SLog.d(TAG, "getTvChannelsFromCae.channel_account == "
					+ channel_account);
			ChannelBean fav;
			// 循环获取频道数据对象
			for (int i = 0; i < channel_account; i++) {
				SLog.d(TAG, "=====================================");
				fav = new ChannelBean();
				int play_time; // 观看时常

				// 读频道id
				byte[] byte2 = new byte[2];
				dis.read(byte2);
				int channel_id = ConnectManager.bytesToShort(byte2);
				fav.setChannel_id(channel_id);
				SLog.d(TAG, "getTvChannelsFromCae.channel_id == " + channel_id);

				// 读名字id
				byte[] byte64 = new byte[64];
				int len = dis.read(byte64);
				String gettedName64 = new String(byte64, 0, len);
				int index = 0;
				for (int j = 0; j < gettedName64.length(); j++) {
					if (0 == (gettedName64.charAt(j))) {
						index = j;
						break;
					}
				}
				String channelName = gettedName64.substring(0, index);
				fav.setChannel_name(channelName);
				SLog.d(TAG, "getTvChannelsFromCae.channelName == "
						+ channelName);

				// 读出播放时间
				play_time = dis.readInt();
				fav.setPlay_time(String.valueOf(play_time));
				SLog.d(TAG, "getTvChannelsFromCae.channel.play_time == "
						+ play_time);
				// 添加到集合频道
				channels.add(fav);
				// 读保留位
				dis.readInt();
				SLog.d(TAG, "======================================");
			}

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return channels;
	}

}
